/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package com.google.code.peersim.pastry.controls;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import peersim.config.Configuration;
import peersim.core.CommonState;
import peersim.dynamics.DynamicNetwork;
import peersim.util.FileNameGenerator;

/**
 * This control class is meant for simulating network churns. It can be dynamically
 * enabled and disabled by other simulation components, and you can control the 
 * window of time during which the {@link PastryChurner} has to be active.
 *
 * @author frusso
 * @version 0.1
 * @since 0.1
 */
public class PastryChurner extends DynamicNetwork {

  /**
   * Configuration property for defining the simulated time starting from which
   * the churn can begin.
   */
  public static final String MIN_SIMULATION_TIME = "minTime";
  /**
   * Configuration property for defining the simulated time starting from which
   * the churn must end.
   */
  public static final String MAX_SIMULATION_TIME = "maxTime";
  /**
   * Configuration property for defining the name of the file this control class
   * should log to.
   */
  public static final String LOG_FILE = "log";
  /**
   * Configuration property for defining whether this control class should log or not.
   */
  public static final String DO_LOG = "doLog";
  /**
   * Tells whether instances of this class are enabled or not.
   */
  private static boolean enabled = false;

  /**
   * Enables all instances of this class.
   */
  public static void enable() {
    enabled = true;
  }

  /**
   * Disables all instances of this class.
   */
  public static void disable() {
    enabled = false;
  }

  private String fileName;
  private PrintStream stream;
  private int minTime;
  private int maxTime;
  private boolean doLog;

  /**
   * Constructor.
   * 
   * @param prefix
   * @throws java.io.FileNotFoundException
   */
  public PastryChurner(String prefix) throws FileNotFoundException {
    super(prefix);
    minTime = Configuration.getInt(prefix+"."+MIN_SIMULATION_TIME);
    maxTime = Configuration.getInt(prefix+"."+MAX_SIMULATION_TIME);
    doLog = Configuration.getBoolean(prefix + "." + DO_LOG);
    if(doLog) {
      fileName = new FileNameGenerator(Configuration.getString(prefix + "."+LOG_FILE), ".log").nextCounterName();
      stream = new PrintStream(new FileOutputStream(fileName));
    }
  }

  /**
   * {@inheritDoc}
   *
   * This method is executed iff the simulation-time is in between {@link PastryChurner#MIN_SIMULATION_TIME}
   * and {@link PastryChurner#MAX_SIMULATION_TIME} and the control class is enabled.
   *
   * @see PastryChurner#enable()
   * @see PastryChurner#disable()
   */
  @Override
  protected void add(int n) {
    if(enabled && isInTime()) {
      if(doLog)
        stream.println(CommonState.getTime()+") adding "+n+" nodes");
      super.add(n);
    }
  }

  /**
   * {@inheritDoc}
   *
   * This method is executed iff the simulation-time is in between {@link PastryChurner#MIN_SIMULATION_TIME}
   * and {@link PastryChurner#MAX_SIMULATION_TIME} and the control class is enabled.
   *
   * @see PastryChurner#enable()
   * @see PastryChurner#disable()
   */
  @Override
  protected void remove(int n) {
    if(enabled && isInTime()) {
      if(doLog)
        stream.println(CommonState.getTime()+") removing "+n+" nodes");
      super.remove(n);
    }
  }

  /**
   * Tells whether the simulation-time is in between {@link PastryChurner#MIN_SIMULATION_TIME}
   * and {@link PastryChurner#MAX_SIMULATION_TIME}.
   *
   * @return Whether we are in the activity-allowed time-window
   */
  private boolean isInTime() {
    return CommonState.getTime()>minTime && CommonState.getTime()<maxTime;
  }
}